#include<iostream>
#include<string>
#include<conio.h>
#include "CustomConsole.h"
using namespace std;

#pragma region 1. 初始化窗口大小
void initWindowSize(int w, int h)
{
	setConsoleSize(w, h);
	setCursorVisibility(false);
}
#pragma endregion

#pragma region 2. 生成红墙和提示字
enum Color
{
	Blue = 1,
	Green = 2,
	Red = 4,
	White = 7,
};

string wallGrid = "■";
string normalGrid = "□";
string pauseGrid = "‖";
string boomGrid = "●";
string tunnelGrid = "¤";
string playerGrid = "★";
string computerGrid = "▲";
string overlapGrid = "◎";

void generateRedWall(int w, int h)
{
	setTextColor(Red);
	// 横向
	for (int i = 0; i < w; i += 2)
	{
		// 第一行
		setCursorPosition(i, 0);
		cout << wallGrid;
		// 最后一行
		setCursorPosition(i, h);
		cout << wallGrid;
		// 倒数第二行
		setCursorPosition(i, h - 5);
		cout << wallGrid;
		// 倒数第三行
		setCursorPosition(i, h - 10);
		cout << wallGrid;
	}
	// 竖向
	for (int i = 0; i < h; i++)
	{
		// 最左侧
		setCursorPosition(0, i);
		cout << wallGrid;
		// 最右侧
		setCursorPosition(w - 2, i);
		cout << wallGrid;
	}
}

void showTipsText(int w, int h)
{
	setCursorPosition(2, h - 9);
	setTextColor(White);
	cout << normalGrid << ": 普通格子";

	setCursorPosition(2, h - 8);
	setTextColor(Blue);
	cout << pauseGrid << ": 暂停一回合";
	cout << "  ";
	setTextColor(Red);
	cout << boomGrid << ": 炸弹, 倒退5格";

	setCursorPosition(2, h - 7);
	setTextColor(Red | Blue);
	cout << tunnelGrid << ": 时空隧道, 人机交换位置";

	setCursorPosition(2, h - 6);
	setTextColor(Red | Green);
	cout << playerGrid << ": 玩家";
	setTextColor(Blue | Green);
	cout << "  " << computerGrid << ": 电脑";
	setTextColor(White);
	cout << "  " << overlapGrid << ": 玩家和电脑位置重合";

	setCursorPosition(2, h - 4);
	setTextColor(White);
	cout << "按任意键开始摇色子...";
}
#pragma endregion

#pragma region 3. 格子枚举和格子结构体相关
//格子的类型
enum E_Grid_Type
{
	Normal,//普通格子
	Boom,//炸弹
	Pause,//暂停
	Tunnel,//时空隧道
};

//位置结构体
struct Vector2
{
	int x;
	int y;

	Vector2()
	{
		x = 0;
		y = 0;
	}

	Vector2(int x, int y) : x(x), y(y) {}
};

//格子结构体
struct Grid
{
	E_Grid_Type type;//格子的类型
	Vector2 pos;//格子的位置

	Grid()
	{
		type = Normal;
		pos = {};
	}

	Grid(int x, int y, E_Grid_Type type)
	{
		pos = { x, y };
		this->type = type;
	}

	//根据格子类型和位置 绘制格子
	void draw()
	{
		//设置格子所在的位置 去进行颜色设置会图像绘制
		setCursorPosition(pos.x, pos.y);
		//根据格子的位置 去绘制对应类型的颜色的图像
		switch (type)
		{
		case Normal:
			setTextColor(White);
			cout << normalGrid;
			break;
		case Boom:
			setTextColor(Red);
			cout << boomGrid;
			break;
		case Pause:
			setTextColor(Blue);
			cout << pauseGrid;
			break;
		case Tunnel:
			setTextColor(Red | Blue);
			cout << tunnelGrid;
			break;
		}
	}
};
#pragma endregion

#pragma region 4. 地图结构体相关
struct Map
{
	Grid* grids = nullptr;//格子数组首地址
	int gridNum;//格子数组数量

	//传入 地图的起始位置 以及 有多少个格子
	Map(int x, int y, int num)
	{
		gridNum = num;
		grids = new Grid[gridNum];

		int indexX = 0;
		int indexY = 0;
		int stepNum = 2;

		int randomNum;
		for (int i = 0; i < gridNum; i++)
		{
			randomNum = getRandom(0, 100);
			if (randomNum < 85 || i == 0 || i == gridNum - 1)
				grids[i].type = Normal;
			else if (85 <= randomNum && randomNum < 90)
				grids[i].type = Boom;
			else if (90 <= randomNum && randomNum < 95)
				grids[i].type = Pause;
			else
				grids[i].type = Tunnel;
			grids[i].pos = Vector2(x, y);

			if (indexX == 10)
			{
				y++;
				indexY++;
				if (indexY == 2)
				{
					indexX = 0;
					indexY = 0;
					stepNum = -stepNum;
				}
			}
			else
			{
				x += stepNum;
				indexX++;
			}
		}
	}

	~Map()
	{
		if (grids != nullptr)
		{
			delete[] grids;
			grids = nullptr;
		}
	}

	//绘制地图
	void draw()
	{
		//通过循环命令自己管理的格子们去执行一个绘制的行为
		for (int i = 0; i < gridNum; i++)
		{
			//调用格子数组中每一个格子的绘制方法
			grids[i].draw();
		}
	}
};
#pragma endregion

#pragma region 5. 玩家相关
enum class ERole
{
	Player,
	Computer
};
struct Player
{
	ERole role;
	int curIndex;
	bool isPause;
	Player(ERole role, int index)
	{
		this->role = role;
		this->curIndex = index;
		isPause = false;
	}
	void draw(Map& mapInfo)
	{
		Grid grid = mapInfo.grids[curIndex];
		setCursorPosition(grid.pos.x, grid.pos.y);
		switch (role)
		{
		case ERole::Player:
			setTextColor(Red | Green);
			cout << playerGrid;
			break;
		case ERole::Computer:
			setTextColor(Green | Blue);
			cout << computerGrid;
			break;
		default:
			break;
		}
	}
};

void drawPlayer(Player& player, Player& otherPlayer, Map& mapInfo)
{
	if (player.curIndex == otherPlayer.curIndex)
	{
		Grid grid = mapInfo.grids[player.curIndex];
		setCursorPosition(grid.pos.x, grid.pos.y);
		setTextColor(White);
		cout << overlapGrid;
	}
	else
	{
		player.draw(mapInfo);
		otherPlayer.draw(mapInfo);
	}
}
#pragma endregion

#pragma region 6. 游戏场景选择
enum EScene
{
	Begin,
	Game,
	End
};

enum EChioce
{
	One,
	Two
};

void beginOrEndScene(int w, int h, EScene& curScene)
{
	setCursorPosition(curScene == Begin ? w / 2 - 3 : w / 2 - 4, h - 22);
	setTextColor(White);
	cout << (curScene == Begin ? "飞行棋" : "游戏结束");

	EChioce curChioce = One;
	bool isLeave = false;
	while (true)
	{
		setCursorPosition(curScene == Begin ? w / 2 - 4 : w / 2 - 5, h - 18);
		setTextColor(curChioce == One ? Red : White);
		cout << (curScene == Begin ? "开始游戏" : "回到主菜单");

		setCursorPosition(w / 2 - 4, h - 16);
		setTextColor(curChioce == Two ? Red : White);
		cout << ("退出游戏");

		int input = _getch();
		switch (input)
		{
		case 'W':
		case 'w':
			curChioce = One;
			break;
		case 'S':
		case 's':
			curChioce = Two;
			break;
		case 'J':
		case 'j':
			switch (curChioce)
			{
			case One:
				curScene = curScene == Begin ? Game : Begin;
				isLeave = true;
				break;
			case Two:
				closeConsole();
				break;
			}
			break;
		}
		if (isLeave)
			break;
	}
}

//擦除提示位置的信息
void clearInfo(int w, int h)
{
	//擦除之前显示的提示信息
	for (int j = 4; j >= 2; j--)
	{
		for (int i = 2; i < w - 2; i++)
		{
			setCursorPosition(i, h - j);
			cout << " ";
		}
	}
}

bool randomMove(int w, int h, Player& player, Player& otherPlayer, Map& mapInfo)
{
	clearInfo(w, h);
	setTextColor(player.role == ERole::Player ? Red | Green : Green | Blue);

	if (player.isPause)
	{
		player.isPause = false;
		setCursorPosition(2, h - 4);
		cout << (player.role == ERole::Player ? "玩家" : "电脑") << "本回合暂停行动";
		return false;
	}
	else
	{
		setCursorPosition(2, h - 4);
		cout << (player.role == ERole::Player ? "玩家开始摇骰子..." : "电脑开始摇骰子...");

		int moveNum = getRandom(1, 6);
		setCursorPosition(2, h - 3);
		cout << "点数: " << moveNum << ", ";

		cout << (player.role == ERole::Player ? "玩家将移动" : "电脑将移动") << moveNum << "格";
		player.curIndex += moveNum;
		if (player.curIndex > mapInfo.gridNum)
		{
			player.curIndex = mapInfo.gridNum;
		}
		Grid grid = mapInfo.grids[player.curIndex];

		switch (grid.type)
		{
		case Normal:
			break;
		case Boom:
			setCursorPosition(2, h - 2);
			cout << "踩到了炸弹, 后退5格";

			player.curIndex -= 5;
			if (player.curIndex < 0)
			{
				player.curIndex = 0;
			}
			break;
		case Pause:
			setCursorPosition(2, h - 2);
			cout << "踩到了暂停格, 下回合不能摇骰子";
			player.isPause = true;
			break;
		case Tunnel:
			setCursorPosition(2, h - 2);
			cout << "踩到了隧道格, 玩家和电脑交换位置";
			int tmp = player.curIndex;
			player.curIndex = otherPlayer.curIndex;
			otherPlayer.curIndex = tmp;
			break;
		}
		return player.curIndex >= mapInfo.gridNum - 1;
	}

}

bool playerRandomMove(int w, int h, Player& player, Player& otherPlayer, Map& mapInfo, EScene& curScene)
{
	_getch();
	bool isOver = randomMove(w, h, player, otherPlayer, mapInfo);
	mapInfo.draw();
	drawPlayer(player, otherPlayer, mapInfo);
	if (isOver)
	{
		setCursorPosition(2, h - 2);
		cout << "游戏结束, " << (player.role == ERole::Player ? "玩家" : "电脑") << "获得了胜利 !";
		setCursorPosition(2, h - 1);
		cout << "按任意键继续...";
		curScene = End;
		_getch();
	}
	return isOver;
}

void gameScene(int w, int h, EScene& curScene)
{
	// 2. 生成红墙
	generateRedWall(w, h);

	// 3. 提示字
	showTipsText(w, h);

	// 4. 画地图
	Map map(14, 3, 80);
	map.draw();

	// 5. 玩家、电脑
	Player player = Player(ERole::Player, 0);
	Player computer = Player(ERole::Computer, 0);
	drawPlayer(player, computer, map);

	while (true)
	{
		if (playerRandomMove(w, h, player, computer, map, curScene))
			break;
		if (playerRandomMove(w, h, computer, player, map, curScene))
			break;
	}
}

#pragma endregion


int main()
{
	int w = 50;
	int h = 30;
	// 1. 初始化窗口大小
	initWindowSize(w, h);

	EScene curScene = EScene::Begin;
	while (true)
	{
		system("cls");
		switch (curScene)
		{
		case Begin:
			beginOrEndScene(w, h, curScene);
			break;
		case Game:
			gameScene(w, h, curScene);
			break;
		case End:
			beginOrEndScene(w, h, curScene);
			break;
		default:
			break;
		}
	}

	return 0;
}